from package import Package
from md5thread import MD5Thread
from qpyshare_share import QPyShare_Share
from PyQt4 import QtCore, QtGui
import os,sys, md5, bz2

#import time,random

class QPyShare_ShareList(QtCore.QObject):
    def __init__(self, parent=None):
        QtCore.QObject.__init__(self, parent)
        
        self.parent = parent
        self.share_list = {}
        
        self.share_pending = False
        self.share_list_pending = []
        
        self.md5t = MD5Thread(self)
        self.connect(self.md5t,QtCore.SIGNAL("finished()"),self.md5t_finished)
        
        self.chunksize = self.parent.settings.value("chunksize").toInt()[0]
        
    def send_addFile(self,share):
       
        pkg = Package("AddFile")
        pkg.add("id",share.id)
        pkg.add("filename",share.filename)
        pkg.add("size", share.size)
        pkg.add("previewType",share.previewType)
        pkg.add("preview",share.preview)
        
        self.parent.sendPkg(pkg)
    
    def addFile_fromLocal(self,filename):
        self.md5t.filename = filename
        self.md5t.start()
        #emit md5 starting
        self.emit(QtCore.SIGNAL("messageMD5(QString)"), filename )
    
    def md5t_finished(self):
        self.addFile_fromLocal_ID(self.md5t.filename,self.md5t.id)

    def addFile_fromLocal_ID(self,filename, id):

        #emit md5 finished
        self.emit(QtCore.SIGNAL("messageMD5Close()"))
        
        if not self.share_list.has_key(id):

            fileinfo = QtCore.QFileInfo(filename)
           
            size = fileinfo.size()
            filename_base = fileinfo.fileName()
            fullFilename = filename
            mode = QPyShare_Share.mode_Upload
        
            share = self.generateShareItem(id,filename_base,fullFilename,size,mode)
            share.generatePreview()
            
            self.send_addFile(share)
            self.emitShareUpdated(share)
            
        else:
            
            #emit archivo ya existe
            share_orig = self.share_list[id]
            self.emit(QtCore.SIGNAL("messageWarning(QString)"),QtCore.QCoreApplication.translate("QPyShare_ShareList","You already have added the file %1 to the share list (same MD5 as %2)").arg(filename,share_orig.filename))
            
            self.processPendingFiles()
        
    def addFile_fromPeer(self,pkg):
        
        self.parent.log(QtCore.QCoreApplication.translate("QPyShare_ShareList","Adding %1 to share list").arg(pkg.get("filename")))
        
        id = pkg.get("id")
        size = pkg.get("size")
        filename = pkg.get("filename")
        fullFilename = unicode(self.parent.settings.value("basepath").toString()) + "/" + pkg.get("filename")
        mode = QPyShare_Share.mode_Download
        previewType = pkg.get("previewType")
        preview = pkg.get("preview")
        
        share = self.generateShareItem(id,filename,fullFilename,size,mode)
        share.setPreview(previewType, preview)
        
        self.emitShareUpdated(share)
        
        pkg = Package("AddFileOK")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)
    
    def generateShareItem(self,id,filename,fullFilename, size, mode):
        
        share = QPyShare_Share(id,filename,fullFilename, size, mode)
        self.share_list[id] = share
        return share
        
    def emitShareUpdated(self,share):
        self.emit(QtCore.SIGNAL("shareUpdated(PyQt_PyObject)"), share)
        
    def emitShareStateUpdated(self,share):
        self.emit(QtCore.SIGNAL("shareStateUpdated(PyQt_PyObject)"), share)
        
    def emitShareFinished(self,share):
        self.emit(QtCore.SIGNAL("shareFinished(PyQt_PyObject)"), share)
        
    def addFilePending(self,filename):
        
        if self.parent.isConnectedHSOK():
            self.share_list_pending = list(self.share_list_pending)
            self.share_list_pending.append(filename)
            
            if not self.share_pending:
                self.processPendingFiles()
            
            return True
        else:
            return False

    def processPendingFiles(self, pkg = None):
        
        if len(self.share_list_pending) > 0:
            self.share_pending = True
            self.addFile_fromLocal(self.share_list_pending.pop(0))
        else:
            self.share_pending = False
            
    def sendFileChunk(self,id):
        
        #if not self.share_list.has_key(id):
        #    print "trying to sendFileChunk of share that doesn't exist - (disconnected?)"
        #    return
        
        share = self.share_list[id]
        if not share.status == QPyShare_Share.status_Paused:
            chunk = share.readData(self.chunksize)
            
            size = len(chunk)
            if size > 0:
                
                pkg = Package("FileData")
                pkg.add("id",id)
                pkg.add("data",chunk)
                self.parent.sendPkg(pkg)
                
                share.addTransferred(size)
                
                self.emitShareUpdated(share)

            else:
                pkg = Package("EOF")
                pkg.add("id",id)
                self.parent.sendPkg(pkg)
        
    def saveFileChunk(self,id,data):
        
        share = self.share_list[id]
        share.writeData(data)
        
        share.addTransferred(len(data))
        
        self.emitShareUpdated(share)

    def startFT(self,id):
        share = self.share_list[id]
        if share.canStartSend():
            if share.mode == QPyShare_Share.mode_Upload:
                
                self.openShare(share)
                
                pkg = Package("StartFileTransfer")
                pkg.add("id",id)
                self.parent.sendPkg(pkg)
                
            else:
                
                pkg = Package("RequestFileTransfer")
                pkg.add("id",id)
                self.parent.sendPkg(pkg)
        
    def openFile(self,id):
        self.openShare(self.share_list[id])
        
    def openShare(self,share):
        share.openFile()
        share.setAsRunning()
        self.emitShareUpdated(share)
        self.emitShareStateUpdated(share)
        
    def closeFT(self,id):

        share = self.share_list[id]
        share.closeFile()
        share.setAsFinished()
        if share.mode == QPyShare_Share.mode_Download:
            self.connect(share, QtCore.SIGNAL("md5check_finished(PyQt_PyObject)"), self.md5check_finished)
            share.checkMD5()
            
        self.emitShareUpdated(share)
        self.emitShareStateUpdated(share)
        self.emitShareFinished(share)
    
    def md5check_finished(self, share):
        if not share.fileOK:
            self.emit(QtCore.SIGNAL("messageWarning(QString)"),QtCore.QCoreApplication.translate("QPyShare_ShareList","MD5 verification of %1 failed. The file is corrupted").arg(share.filename))
        
    def clearList(self):
        for share_id in self.share_list.keys():
            share = self.share_list[share_id]
            if share.isOpen():
                share.closeFile()
            self.emit(QtCore.SIGNAL("shareDeleted(QString)"), share_id)
            del self.share_list[share_id]

    def pauseShare(self, id):
        share = self.share_list[id]
        share.setAsPaused()
        self.emitShareUpdated(share)
        self.emitShareStateUpdated(share)
        
    def resumeShare(self,id):
        share = self.share_list[id]
        share.setAsRunning()
        self.emitShareUpdated(share)
        self.emitShareStateUpdated(share)
        if share.mode == QPyShare_Share.mode_Upload:
            self.sendFileChunk(id)
        
    #---------------
    #---------------
    #(Share related) 
    #COMMANDS PROCESSING
    #---------------
    
    #------------PAUSE SHARE
    
    def cmd_send_PauseShare(self,id):
        
        pkg = Package("PauseShare")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)
        
    def cmd_recv_PauseShare_send_PauseShareOK(self,orig_pkg):
        id = orig_pkg.get("id")
        self.pauseShare(id)
        
        pkg = Package("PauseShareOK")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)
        
    def cmd_recv_PauseShareOK(self,orig_pkg):
        self.pauseShare(orig_pkg.get("id"))
        
    #------------RESUME SHARE
    
    def cmd_send_ResumeShare(self,id):
        self.resumeShare(id)
        pkg = Package("ResumeShare")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)
        
    def cmd_recv_ResumeShare_send_ResumeShareOK(self,orig_pkg):
        self.resumeShare(orig_pkg.get("id"))
        
    #------------FILEDATA
    
    #Recibo fileData,  guardo, envio FileDataOK
    def cmd_recv_FileData_send_FileDataOK(self,orig_pkg):
        
        id = orig_pkg.get("id")
        self.saveFileChunk(id,orig_pkg.get("data"))
        
        pkg = Package("FileDataOK")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)
    
    #Recibo fileDataOK, leo, envio FileChunk o EOF
    def cmd_recv_FileDataOK_send_FileChunk(self,orig_pkg):
        
        id = orig_pkg.get("id")
        self.sendFileChunk(id)

    #------------ FINISH FILE TRANSFER
    
    #Recibo EOF, cierro, envio EOFOK
    def cmd_recv_EOF_send_EOFOK(self,orig_pkg):
        id = orig_pkg.get("id")
        self.closeFT(id)
        
        pkg = Package("EOFOK")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)
        
    #Recibo EOFOK, cierro
    def cmd_recv_EOFOK_close(self,orig_pkg):
        id = orig_pkg.get("id")
        self.closeFT(id)

    #------------ START FILE TRANSFER
        
    #Recibo RequestFileTransfer envio StartFileTransfer
    def cmd_recv_RequestFileTransfer_send_StartFileTransfer(self, orig_pkg):
        self.startFT(orig_pkg.get("id"))
        
    #Recibo StartFileTransfer envio StartFileTransferOK
    def cmd_recv_StartFileTransfer_send_StartFileTransferOK(self,orig_pkg):
        
        id = orig_pkg.get("id")
        self.openFile(id)
        
        pkg = Package("StartFileTransferOK")
        pkg.add("id",id)
        self.parent.sendPkg(pkg)